80386响应 中断/异常 的优先级 |
中断/异常类型 | 优先级 |
调试故障 | 最高 | |
其它故障 | ↓ | |
陷阱指令INT n和INTO | ↓ | |
调试陷阱 | ↓ | |
NMI中断 | ↓ | |
INTR中断 | 最低 |
异 常 一 览 表 |
向量号 | 异常名称 | 异常类型 | 出错代码 | 相关指令 |
0 | 除法出错 | 故障 | 无 | DIV,IDIV | |
1 | 调试异常 | 故障/陷阱 | 无 | 任何指令 | |
3 | 单字节INT3 | 陷阱 | 无 | INT 3 | |
4 | 溢出 | 陷阱 | 无 | INTO | |
5 | 边界检查 | 故障 | 无 | BOUNT | |
6 | 非法操作码 | 故障 | 无 | 非法指令编码或操作数 | |
7 | 设备不可用 | 故障 | 无 | 浮点指令或WAIT | |
8 | 双重故障 | 中止 | 有 | 任何指令 | |
9 | 协处理器段越界 | 中止 | 无 | 访问存储器的浮点指令 | |
0AH | 无效TSS异常 | 故障 | 有 | JMP、CALL、IRET或中断 | |
0BH | 段不存在 | 故障 | 有 | 装载段寄存器的指令 | |
0CH | 堆栈段异常 | 故障 | 有 | 装载SS寄存器的任何指令、对SS寻址的段访问的任何指令 | |
0DH | 通用保护异常 | 故障 | 有 | 任何特权指令、任何访问存储器的指令 | |
0EH | 页异常 | 故障 | 有 | 任何访问存储器的指令 | |
10H | 协处理器出错 | 故障 | 无 | 浮点指令或WAIT | |
11H—0FFH | 软中断 | 陷阱 | 无 | INT n |
出错代码的格式 | |||
BIT15—BIT3 | BIT2 | BIT1 | BIT0 |
选择子的索引部分 | TI | IDT | EXT |
;名称:ASM6.ASM ;功能:演示中断处理的实现 ;编译:TASM ASM6.ASM ;连接:TLINK ASM6.OBJ ;---------------------------------------------------------------------------- INCLUDE 386SCD.INC ;---------------------------------------------------------------------------- ;部分常量定义 ;---------------------------------------------------------------------------- EOICOM = 20h ;外部中断处理结束命令 ICREGP = 20h ;中断控制寄存器端口地址 IMREGP = 21h ;中断屏蔽寄存器端口地址 ;---------------------------------------------------------------------------- GDTSeg SEGMENT PARA USE16 ;全局描述符表数据段(16位) ;---------------------------------------------------------------------------- ;全局描述符表GDT GDT LABEL BYTE ;空描述符 DUMMY Desc <> ;规范段描述符 Normal Desc <0ffffh,,,ATDW,,> ;视频缓冲区段描述符(DPL=3) VideoBuf Desc <0ffffh,8000h,0bh,ATDW,,> ;---------------------------------------------------------------------------- EFFGDT LABEL BYTE ;临时代码段描述符 TempCode Desc <0ffffh,TempCodeSeg,,ATCE,,> ;演示代码段描述符 DemoCode Desc <DemoCodeLen-1,DemoCodeSeg,,ATCE,,> ;演示数据段描述符 DemoData Desc <DemoDataLen-1,DemoDataSeg,,ATDW,,> ;演示堆栈段描述符 DemoStack Desc <DemoStackLen-1,DemoStackSeg,,ATDWA,,> ;0feh号中断处理程序(显示程序)代码段描述符 EchoCode Desc <EchoCodeLen-1,EchoCodeSeg,,ATCE,,> ;0feh号中断处理程序(显示程序)数据段描述符 EchoData Desc <EchoDataLen-1,EchoDataSeg,,ATDW,,> ;8号中断处理程序代码段描述符 TICode Desc <TICodeLen-1,TICodeSeg,,ATCE,,> ;8号中断处理程序数据段描述符 TIData Desc <TIDataLen-1,TIDataSeg,,ATDW,,> ;其它中断或异常处理程序代码段描述符 Other Desc <OtherCodeLen-1,OtherCodeSeg,,ATCE,,> ;---------------------------------------------------------------------------- GDTLen = $-GDT ;全局描述符表长度 GDNum = ($-EFFGDT)/(SIZE Desc) ;需特殊处理的描述符数 ;---------------------------------------------------------------------------- Normal_Sel = Normal-GDT ;规范段描述符选择子 Video_Sel = VideoBuf-GDT ;视频缓冲区段描述符选择子 ;---------------------------------------------------------------------------- TempCode_Sel = TempCode-GDT ;临时代码段的选择子 DemoCode_Sel = DemoCode-GDT ;演示代码段的选择子 DemoData_Sel = DemoData-GDT ;演示数据段的选择子 DemoStack_Sel = DemoStack-GDT ;演示堆栈段的选择子 EchoCode_Sel = EchoCode-GDT ;0feh号中断程序代码段选择子 EchoData_Sel = EchoData-GDT ;0feh号中断程序数据段选择子 TICode_Sel = TICode-GDT ;8号中断程序代码段选择子 TIData_Sel = TIData-GDT ;8号中断程序数据段选择子 Other_Sel = Other-GDT ;其它中断或异常代码段选择子 ;---------------------------------------------------------------------------- GDTSeg ENDS ;全局描述符表段定义结束 ;---------------------------------------------------------------------------- IDTSeg SEGMENT PARA USE16 ;中断描述符表数据段(16位) ;---------------------------------------------------------------------------- IDT LABEL BYTE ;中断描述符表 ;0--7的8个陷阱门描述符 REPT 8 Gate <OtherBegin,Other_Sel,,AT386TGate,> ENDM ;对应8号(时钟)中断处理程序的门描述符 Gate <TIBegin,TICode_Sel,,AT386IGate,> ;从9--0fdh的245个陷阱门描述符 REPT 245 Gate <OtherBegin,Other_Sel,,AT386TGate,> ENDM ;对应0feh号中断处理程序的陷阱门描述符 Gate <EchoBegin,EchoCode_Sel,,AT386TGate,> ;对应0ffh号中断处理程序的陷阱门描述符 Gate <OtherBegin,Other_Sel,,AT386TGate,> ;---------------------------------------------------------------------------- IDTLen = $-IDT ;---------------------------------------------------------------------------- IDTSeg ENDS ;中断描述符表段定义结束 ;---------------------------------------------------------------------------- ;其它中断或异常处理程序的代码段 ;---------------------------------------------------------------------------- OtherCodeSeg SEGMENT PARA USE16 ASSUME CS:OtherCodeSeg ;---------------------------------------------------------------------------- OtherBegin PROC FAR mov ax,Video_Sel mov es,ax mov ah,17h ;在屏幕左上角显示兰底白字 mov al,'!' ;符号"!" mov WORD PTR es:[0],ax jmp $ ;无限循环 OtherBegin ENDP ;---------------------------------------------------------------------------- OtherCodeLen = $ OtherCodeSeg ENDS ;---------------------------------------------------------------------------- ;8号中断处理程序的数据段 ;---------------------------------------------------------------------------- TIDataSeg SEGMENT PARA USE16 Count DB 0 ;中断发生的计数器 TIDataLen = $ TIDataSeg ENDS ;---------------------------------------------------------------------------- ;8号中断处理程序的代码段 ;---------------------------------------------------------------------------- TICodeSeg SEGMENT PARA USE16 ASSUME CS:TICodeSeg,DS:TIDataSeg ;---------------------------------------------------------------------------- TIBegin PROC FAR push eax ;保护现场 push ds push fs push gs mov ax,TIData_Sel ;置中断处理程序数据段 mov ds,ax mov ax,EchoData_Sel ;置显示过程数据段 mov fs,ax mov ax,DemoData_Sel ;置演示程序数据段 mov gs,ax cmp Count,0 jnz TI2 ;计数非0表示未到1秒 mov Count,18 ;每秒约18次 int 0feh ;调用0FEH号中断处理程序显示 cmp BYTE PTR fs:Mess,'0' jnz TI1 mov BYTE PTR gs:Flag,1 ;显示符号'0'时置标记 TI1: dec BYTE PTR fs:Mess ;调整显示符号 TI2: dec Count ;调整计数 pop gs ;恢复现场 pop fs pop ds mov al,EOICOM ;通知中断控制器中断处理结束 out ICREGP,al pop eax iretd ;中断返回 TIBegin ENDP ;---------------------------------------------------------------------------- TICodeLen = $ TICodeSeg ENDS ;---------------------------------------------------------------------------- ;0FEH号中断处理程序数据段 ;---------------------------------------------------------------------------- EchoDataSeg SEGMENT PARA USE16 Mess DB '8',4eh EchoDataLen = $ EchoDataSeg ENDS ;---------------------------------------------------------------------------- ;0FEH号中断处理程序(显示程序)的代码段 ;---------------------------------------------------------------------------- EchoCodeSeg SEGMENT PARA USE16 ASSUME CS:EchoCodeSeg,DS:EchoDataSeg ;---------------------------------------------------------------------------- EchoBegin PROC FAR push ax ;保护现场 push ds push es mov ax,EchoData_Sel ;置显示过程数据段 mov ds,ax mov ax,Video_Sel ;置视频缓冲区数据段 mov es,ax mov ax,WORD PTR Mess mov WORD PTR es:[0],ax pop es pop ds pop ax iretd EchoBegin ENDP ;---------------------------------------------------------------------------- EchoCodeLen = $ EchoCodeSeg ENDS ;---------------------------------------------------------------------------- ;演示任务的堆栈段 ;---------------------------------------------------------------------------- DemoStackSeg SEGMENT PARA USE16 DemoStackLen = 1024 DB DemoStackLen DUP(0) DemoStackSeg ENDS ;---------------------------------------------------------------------------- ;演示任务的数据段 ;---------------------------------------------------------------------------- DemoDataSeg SEGMENT PARA USE16 Flag DB 0 DemoDataLen = $ DemoDataSeg ENDS ;---------------------------------------------------------------------------- ;演示任务的代码段 ;---------------------------------------------------------------------------- DemoCodeSeg SEGMENT PARA USE16 ASSUME CS:DemoCodeSeg,DS:DemoDataSeg ;---------------------------------------------------------------------------- DemoBegin PROC FAR mov ax,DemoStack_Sel ;置堆栈 mov ss,ax mov sp,DemoStackLen ;置数据段 mov ax,DemoData_Sel mov ds,ax mov es,ax mov fs,ax mov gs,ax mov al,11111110b ;置中断屏蔽字 out IMREGP,al ;只开发时钟中断 sti ;开中断 DemoConti: cmp BYTE PTR Flag,0 ;判标志 jz DemoConti ;直到不为0 cli ;关中断 ;转回临时代码段,准备回实方式 JUMP16 TempCode_Sel,<OFFSET ToDos> DemoBegin ENDP ;---------------------------------------------------------------------------- DemoCodeLen = $ DemoCodeSeg ENDS ;---------------------------------------------------------------------------- TempCodeSeg SEGMENT PARA USE16 ;临时任务的代码段 ASSUME CS:TempCodeSeg ;---------------------------------------------------------------------------- Virtual PROC FAR JUMP16 DemoCode_Sel,DemoBegin ;转演示任务 ToDos: mov ax,Normal_Sel ;恢复实方式段描述符高速缓存 mov ds,ax mov es,ax mov fs,ax mov gs,ax mov ss,ax mov eax,cr0 ;准备返回实模式 and al,11111110b mov cr0,eax JUMP16 <SEG Real>,<OFFSET Real> Virtual ENDP ;---------------------------------------------------------------------------- TempCodeSeg ENDS ;============================================================================ RDataSeg SEGMENT PARA USE16 ;实方式数据段 VGDTR PDesc <GDTLen-1,> ;GDT伪描述符 VIDTR PDesc <IDTLen-1,> ;IDT伪描述符 NORVIDTR PDesc <3ffh,> ;用于保存原IDTR值 SPVar DW ? ;用于保存实方式下的SP SSVar DW ? ;用于保存实方式下的SS IMaskRegV DB ? ;用于保存原中断屏蔽寄存器值 RDataSeg ENDS ;---------------------------------------------------------------------------- RCodeSeg SEGMENT PARA USE16 ;实方式代码段 ASSUME CS:RCodeSeg,DS:RDataSeg ;---------------------------------------------------------------------------- Start PROC mov ax,RDataSeg mov ds,ax cld call InitGDT ;初始化全局描述符表GDT call InitIDT ;初始化中断描述符表IDT mov SSVar,ss ;保存堆栈指针 mov SPVar,sp sidt QWORD PTR NORVIDTR ;保存IDTR in al,IMREGP mov BYTE PTR IMaskRegV,al lgdt QWORD PTR VGDTR ;装载GDTR cli ;关中断 lidt QWORD PTR VIDTR ;装载IDTR mov eax,cr0 or al,1 mov cr0,eax JUMP16 <TempCode_Sel>,<OFFSET Virtual> Real: mov ax,RDataSeg mov ds,ax lss sp,DWORD PTR SPVar ;又回到实方式 lidt QWORD PTR NORVIDTR mov al,IMaskRegV out IMREGP,al sti mov ax,4c00h int 21h Start ENDP ;---------------------------------------------------------------------------- InitGDT PROC push ds mov ax,GDTSeg mov ds,ax mov cx,GDNum mov si,OFFSET EFFGDT InitG: mov ax,[si].BaseL movzx eax,ax shl eax,4 shld edx,eax,16 mov WORD PTR [si].BaseL,ax mov BYTE PTR [si].BaseM,dl mov BYTE PTR [si].BaseH,dh add si,SIZE Desc loop InitG pop ds mov bx,16 mov ax,GDTSeg mul bx mov WORD PTR VGDTR.Base,ax mov WORD PTR VGDTR.Base+2,dx ret InitGDT ENDP ;---------------------------------------------------------------------------- InitIDT PROC mov bx,16 mov ax,IDTSeg mul bx mov WORD PTR VIDTR.Base,ax mov WORD PTR VIDTR.Base+2,dx ret InitIDT ENDP ;---------------------------------------------------------------------------- RCodeSeg ENDS END Start
sidt QWORD PTR NORVIDTR
lidt QWORD PTR VIDTR lidt QWORD PTR NORVIDTR
;名称:ASM7.ASM ;功能:模拟异常和演示异常处理 ;编译:TASM ASM7.ASM ;连接:TLINK ASM7.OBJ ;---------------------------------------------------------------------------- INCLUDE 386SCD.INC ;---------------------------------------------------------------------------- GDTSeg SEGMENT PARA USE16 ;全局描述符表数据段(16位) ;---------------------------------------------------------------------------- ;全局描述符表GDT GDT LABEL BYTE ;空描述符 DUMMY Desc <> ;规范段描述符及选择子 Normal Desc <0ffffh,,,ATDW,,> Normal_Sel = Normal-GDT ;视频缓冲区段描述符(DPL=3)及选择子 VideoBuf Desc <0ffffh,8000h,0bh,ATDW,,> VideoBuf_Sel = VideoBuf-GDT ;---------------------------------------------------------------------------- EFFGDT LABEL BYTE ;临时代码段描述符及选择子 TempCode Desc <0ffffh,TempCodeSeg,,ATCE,,> TempCode_Sel = TempCode-GDT ;演示代码段描述符及选择子 DemoCode Desc <DemoCodeLen-1,DemoCodeSeg,,ATCE,,> DemoCode_Sel = DemoCode-GDT ;演示任务局部描述符表段描述符及选择子 DemoLDT Desc <DemoLDTLen-1,DemoLDTSeg,,ATLDT,,> DemoLDT_Sel = DemoLDT-GDT ;演示任务TSS段描述符及选择子 DemoTSS Desc <DemoTSSLen-1,DemoTSSSeg,,AT386TSS,,> DemoTSS_Sel = DemoTSS-GDT ;缓冲数据段描述符及选择子 XBuffer Desc <BufferLen-1,BufferSeg,,ATDW,,> XBuffer_Sel = XBuffer-GDT ;读键盘任务局部描述符表段描述符及选择子 GKeyLDT Desc <GKeyLDTLen-1,GKeyLDTSeg,,ATLDT,,> GKeyLDT_Sel = GKeyLDT-GDT ;读键盘任务TSS段描述符及选择子 GKeyTSS Desc <GKeyTSSLen-1,GKeyTSSSeg,,AT386TSS,,> GKeyTSS_Sel = GKeyTSS-GDT ;显示陷阱处理程序代码段描述符及选择子 EchoCode Desc <EchoCodeLen-1,EchoCodeSeg,,ATCE,,> EchoCode_Sel = EchoCode-GDT ;显示出错码过程代码段描述符及选择子 SubCode Desc <SubCodeLen-1,SubCodeSeg,,ATCE,,> SubCode_Sel = SubCode-GDT ;其它中断或异常处理程序代码段描述符及选择子 Other Desc <OtherCodeLen-1,OtherCodeSeg,,ATCE,,> Other_Sel = Other-GDT ;---------------------------------------------------------------------------- GDTLen = $-GDT ;全局描述符表长度 GDNum = ($-EFFGDT)/(SIZE Desc) ;需处理基地址的描述符个数 ;---------------------------------------------------------------------------- GDTSeg ENDS ;全局描述符表段定义结束 ;---------------------------------------------------------------------------- IDTSeg SEGMENT PARA USE16 ;中断描述符表数据段(16位) ;---------------------------------------------------------------------------- IDT LABEL BYTE ;中断描述符表 ;0号陷阱门描述符(对应除法出错故障) Gate <DivBegin,Divide_Sel,,AT386TGate,> ;从1--3的3个陷阱门描述符 REPT 3 Gate <OtherBegin,Other_Sel,,AT386TGate,> ENDM ;4号陷阱门描述符(对应溢出陷阱) Gate <OFBegin,OF_Sel,,AT386TGate,> ;从5--0ah的的6个陷阱门描述符 REPT 6 Gate <OtherBegin,Other_Sel,,AT386TGate,> ENDM ;0bh号陷阱门描述符(对应段不存在故障) Gate <SNPBegin,SNP_Sel,,AT386TGate,> ;0ch号陷阱门描述符(对应堆栈段故障) Gate <SSEBegin,SSE_Sel,,AT386TGate,> ;0dh号陷阱门描述符(对应通用保护故障) Gate <GPBegin,GP_Sel,,AT386TGate,> ;从0eh--0edh的240个陷阱门描述符 REPT 240 Gate <OtherBegin,Other_Sel,,AT386TGate,> ENDM ;对应0feh号陷阱门描述符(对应显示中断处理程序) Gate <EchoBegin,EchoCode_Sel,,AT386TGate,> ;0ffh号任务门描述符(对应读键盘中断处理任务) Gate <,GKeyTSS_Sel,,ATTaskGate,> ;---------------------------------------------------------------------------- IDTLen = $-IDT ;---------------------------------------------------------------------------- IDTSeg ENDS ;中断描述符表段定义结束 ;---------------------------------------------------------------------------- ;读键盘任务局部描述符表段 ;---------------------------------------------------------------------------- GKeyLDTSeg SEGMENT PARA USE16 ;---------------------------------------------------------------------------- GLDT LABEL BYTE ;代码段描述符及选择子 GKeyCode Desc <0ffffh,GKeyCodeSeg,,ATCE,,> GKeyCode_Sel = GKeyCode-GLDT+TIL ;堆栈段描述符及选择子 GKeyStack Desc <GKeyStackLen-1,GKeyStackSeg,,ATDWA,,> GKeyStack_Sel = GKeyStack-GLDT+TIL ;---------------------------------------------------------------------------- GKeyLDNum = ($-GLDT)/(SIZE Desc) ;需初始化基地址的描述符个数 GKeyLDTLen = $ ;局部描述符表段长度 ;---------------------------------------------------------------------------- GKeyLDTSeg ENDS ;---------------------------------------------------------------------------- ;读键盘任务TSS段 ;---------------------------------------------------------------------------- GKeyTSSSeg SEGMENT PARA USE16 DD 0 ;链接字 DD ? ;0级堆栈指针 DW ?,? DD ? ;1级堆栈指针 DW ?,? DD ? ;2级堆栈指针 DW ?,? DD 0 ;CR3 DW GKeyBegin,0 ;EIP DD 0 ;EFLAGS DD 0 ;EAX DD 0 ;ECX DD 0 ;EDX DD 0 ;EBX DW GKeyStackLen,0 ;ESP DD 0 ;EBP DD 0 ;ESI DD 0 ;EDI DW Normal_Sel,0 ;ES DW GKeyCode_Sel,0 ;CS DW GKeyStack_Sel,0 ;SS DW Normal_Sel,0 ;DS DW Normal_Sel,0 ;FS DW Normal_Sel,0 ;GS DW GKeyLDT_Sel,0 ;LDTR DW 0 ;调试陷阱标志 DW $+2 ;指向I/O许可位图的偏移 DB 0ffh ;I/O许可位图结束字节 GKeyTSSLen = $ GKeyTSSSeg ENDS ;---------------------------------------------------------------------------- ;读键盘任务堆栈段 ;---------------------------------------------------------------------------- GKeyStackSeg SEGMENT PARA USE16 GKeyStackLen = 1024 DB GKeyStackLen DUP(0) GKeyStackSeg ENDS ;---------------------------------------------------------------------------- ;读键盘任务代码段 ;---------------------------------------------------------------------------- GKeyCodeSeg SEGMENT PARA USE16 ASSUME CS:GKeyCodeSeg,DS:RDataSeg,ES:BufferSeg ;---------------------------------------------------------------------------- GKeyBegin PROC FAR push ds push es push fs push gs mov ax,Normal_Sel mov ss,ax ;准备转实方式 mov eax,cr0 and al,11111110b mov cr0,eax ;转实方式 JUMP16 <SEG GetKey>,<OFFSET GetKey> GetKey: mov ax,RDataSeg ;实方式 mov ds,ax mov ebp,esp ;恢复实方式部分现场 lss sp,DWORD PTR SPVar lidt QWORD PTR NORVIDTR sti mov dx,OFFSET Mess mov ah,9 int 21h ;显示提示信息 GetKey1: mov ah,0 int 16h ;读键盘 cmp al,'0' jz GetKey2 cmp al,'4' jz GetKey2 and al,11011111b ;小写转大写 cmp al,'B' jb GetKey1 cmp al,'D' ja GetKey1 ;只有[0,4,b,c,d]有效 GetKey2: mov dl,al mov ah,2 int 21h ;显示所按字符 mov ax,BufferSeg mov es,ax mov BYTE PTR es:KeyASCII,dl ;保存到缓冲数据段 cli ;准备返回保护方式 lidt QWORD PTR VIDTR mov eax,cr0 or al,1 mov cr0,eax JUMP16 <GKeyCode_Sel>,<OFFSET GetKeyV> GetKeyV: mov ax,GKeyStack_Sel ;又进入保护方式 mov ss,ax mov esp,ebp pop gs pop fs pop es pop ds iretd jmp GKeyBegin GKeyBegin ENDP ;---------------------------------------------------------------------------- GKeyCodeLen = $ GKeyCodeSeg ENDS ;---------------------------------------------------------------------------- ;其它中断或异常处理程序的代码段 ;---------------------------------------------------------------------------- OtherCodeSeg SEGMENT PARA USE16 ASSUME CS:OtherCodeSeg ;---------------------------------------------------------------------------- OtherBegin PROC FAR mov si,OFFSET MessOther int 0feh ;显示提示信息 mov WORD PTR es:[0],ax jmp $ ;进入无限循环 OtherBegin ENDP ;---------------------------------------------------------------------------- OtherCodeLen = $ OtherCodeSeg ENDS ;---------------------------------------------------------------------------- ;除法出错故障处理程序代码段 ;---------------------------------------------------------------------------- DivCodeSeg SEGMENT PARA USE16 ASSUME CS:DivCodeSeg ;---------------------------------------------------------------------------- DivBegin PROC FAR mov si,OFFSET Mess0 mov di,0 int 0feh ;显示提示信息 shr ax,1 ;处理模拟的除法错误 iretd ;返回 DivBegin ENDP ;---------------------------------------------------------------------------- DivCodeLen = $ DivCodeSeg ENDS ;---------------------------------------------------------------------------- ;溢出陷阱处理程序代码段 ;---------------------------------------------------------------------------- OFCodeSeg SEGMENT PARA USE16 ASSUME CS:OFCodeSeg ;---------------------------------------------------------------------------- OFBegin PROC FAR mov si,OFFSET Mess4 mov di,0 int 0feh ;显示提示信息 iretd ;返回 OFBegin ENDP ;---------------------------------------------------------------------------- OFCodeLen = $ OFCodeSeg ENDS ;---------------------------------------------------------------------------- ;段不存在故障处理程序代码段 ;---------------------------------------------------------------------------- SNPCodeSeg SEGMENT PARA USE16 ASSUME CS:SNPCodeSeg ;---------------------------------------------------------------------------- SNPBegin PROC FAR mov si,OFFSET MessB mov di,0 int 0feh ;显示提示信息 pop eax ;弹出出错代码 CALL16 SubCode_Sel,SubBegin ;显示出错代码 pop eax add eax,2 ;按模拟的引起段不存在指令 push eax ;调整返回地址 iretd SNPBegin ENDP ;---------------------------------------------------------------------------- SNPCodeLen = $ SNPCodeSeg ENDS ;---------------------------------------------------------------------------- ;堆栈段故障处理程序代码段 ;---------------------------------------------------------------------------- SSECodeSeg SEGMENT PARA USE16 ASSUME CS:SSECodeSeg ;---------------------------------------------------------------------------- SSEBegin PROC FAR mov si,OFFSET MessC mov di,0 int 0feh ;显示提示信息 pop eax ;弹出出错代码 CALL16 SubCode_Sel,SubBegin ;显示出错代码 pop eax add eax,4 ;按模拟的引起堆栈段错误的 push eax ;指令调整返回地址 iretd SSEBegin ENDP ;---------------------------------------------------------------------------- SSECodeLen = $ SSECodeSeg ENDS ;---------------------------------------------------------------------------- ;通用保护故障处理程序代码段 ;---------------------------------------------------------------------------- GPCodeSeg SEGMENT PARA USE16 ASSUME CS:GPCodeSeg ;---------------------------------------------------------------------------- GPBegin PROC FAR push ebp mov ebp,esp push eax push esi push edi ;保护现场 mov si,OFFSET MessD mov di,0 int 0feh ;显示提示信息 mov eax,[bp+4] ;从堆栈中取出出错代码 CALL16 SubCode_Sel,SubBegin ;显示出错代码 pop edi pop esi pop eax ;恢复部分现场 add DWORD PTR [ebp+8],2 ;按模拟的故障指令调整返回 pop ebp ;地址 add esp,4 ;废除堆栈中的出错代码 iretd GPBegin ENDP ;---------------------------------------------------------------------------- ;显示出错码过程代码段 ;---------------------------------------------------------------------------- SubCodeSeg SEGMENT PARA USE16 ASSUME CS:SubCodeSeG ;---------------------------------------------------------------------------- SubBegin PROC ;AX中含出错代码 push ax ;保护现场 push cx push dx push si push di mov si,OFFSET ErrCode mov dx,ax mov cx,4 SubR1: rol dx,4 ;把16位出错代码转换成4位 mov al,dl ;十六进制数的ASCII码并保存 and al,0fh add al,30h cmp al,'9' jbe SubR2 add al,7 SubR2: mov [si],al inc si loop SubR1 mov si,OFFSET ErrMess Mov di,80*2 ;从第二行行首开始 int 0feh ;显示出错码 pop di ;恢复现场 pop si pop dx pop cx pop ax retf ;返回 SubBegin ENDP ;---------------------------------------------------------------------------- SubCodeLen = $ SubCodeSeg ENDS ;---------------------------------------------------------------------------- GPCodeLen = $ GPCodeSeg ENDS ;---------------------------------------------------------------------------- ;实现显示的陷阱处理程序代码段 ;入口参数--DS:SI指向显示信息串,ES:DI指向显示缓冲区 ;---------------------------------------------------------------------------- EchoCodeSeg SEGMENT PARA USE16 ASSUME CS:EchoCodeSeg ;---------------------------------------------------------------------------- EchoBegin PROC FAR pushad ;保护现场 cld mov ah,7 mov al,20h mov cx,80 push di rep stosw ;清所在显示行 pop di Echo1: lodsb or al,al jz Echo2 stosw ;显示指定信息串 jmp Echo1 Echo2: popad ;恢复现场 iretd EchoBegin ENDP ;---------------------------------------------------------------------------- EchoCodeLen = $ EchoCodeSeg ENDS ;---------------------------------------------------------------------------- ;缓冲区数据段 ;---------------------------------------------------------------------------- BufferSeg SEGMENT PARA USE16 KeyASCII DB ? Buffer DB 128 DUP(?) BufferLen = $ BufferSeg ENDS ;---------------------------------------------------------------------------- ;演示任务局部描述符表段 ;---------------------------------------------------------------------------- DemoLDTSeg SEGMENT PARA USE16 ;---------------------------------------------------------------------------- DLDT LABEL BYTE ;演示任务TSS段作为数据段的描述符及选择子 ToDemoTSS Desc <DemoTSSLen-1,DemoTSSSeg,,ATDW,,> ToDemoTSS_Sel = ToDemoTSS-DLDT+TIL ;演示任务堆栈段描述符及选择子 DemoStack Desc <DemoStackLen-1,DemoStackSeg,,ATDWA,,> DemoStack_Sel = DemoStack-DLDT+TIL ;演示任务数据段描述符及选择子 DemoData Desc <DemoDataLen-1,DemoDataSeg,,ATDW,,> DemoData_Sel = DemoData-DLDT+TIL ;除法出错故障处理程序代码段描述符及选择子 Divide Desc <DivCodeLen-1,DivCodeSeg,,ATCE,,> Divide_Sel = Divide-DLDT+TIL ;溢出陷阱处理程序代码段描述符及选择子 OverFlow Desc <OFCodeLen-1,OFCodeSeg,,ATCE,,> OF_Sel = OverFlow-DLDT+TIL ;段不存在故障处理程序代码段描述符及选择子 SNPCode Desc <SNPCodeLen-1,SNPCodeSeg,,ATCE,,> SNP_Sel = SNPCode-DLDT+TIL ;堆栈段出错故障处理程序代码段描述符及选择子 SSECode Desc <SSECodeLen-1,SSECodeSeg,,ATCE,,> SSE_Sel = SSECode-DLDT+TIL ;通用保护故障处理程序代码段描述符及选择子 GPCode Desc <GPCodeLen-1,GPCodeSeg,,ATCE,,> GP_Sel = GPCode-DLDT+TIL ;为模拟段不存在故障而安排的数据段描述符及选择子 TestNPS Desc <0ffffh,,,ATDW-80h,,> TestNPS_Sel = TestNPS-DLDT+TIL ;---------------------------------------------------------------------------- DemoLDNum = ($-DLDT)/(SIZE Desc) ;LDT描述符个数 DemoLDTLen =$ ;---------------------------------------------------------------------------- DemoLDTSeg ENDS ;---------------------------------------------------------------------------- ;演示任务TSS段 ;---------------------------------------------------------------------------- DemoTSSSeg SEGMENT PARA USE16 DemoTaskSS TSS <> DB 0ffh DemoTSSLen = $ DemoTSSSeg ENDS ;---------------------------------------------------------------------------- ;演示任务的堆栈段 ;---------------------------------------------------------------------------- DemoStackSeg SEGMENT PARA USE16 DemoStackLen = 1024 DB DemoStackLen DUP(0) DemoStackSeg ENDS ;---------------------------------------------------------------------------- ;演示任务的数据段 ;---------------------------------------------------------------------------- DemoDataSeg SEGMENT PARA USE16 Mess0 DB 'Divide Error (Exception 0)',0 Mess4 DB 'Overflow (Exception 4)',0 MessB DB 'Segment Not Present (Exception 11)',0 MessC DB 'Stack Segment (Exception 12)',0 MessD DB 'General Protection (Exception 13)',0 MessOther DB 'Other Exception',0 ErrMess DB 'Error Code = ' ErrCode DB 4 DUP(0),'H',0 DemoDataLen = $ DemoDataSeg ENDS ;---------------------------------------------------------------------------- ;演示任务的代码段 ;---------------------------------------------------------------------------- DemoCodeSeg SEGMENT PARA USE16 ASSUME CS:DemoCodeSeg,DS:DemoDataSeg ;---------------------------------------------------------------------------- DemoBegin PROC FAR mov ax,DemoLDT_Sel lldt ax ;装载LDTR mov ax,DemoStack_Sel ;置堆栈 mov ss,ax mov esp,DemoStackLen mov ax,ToDemoTSS_Sel mov gs,ax ;把演示任务LDT选择子填入TSS mov WORD PTR gs:DemoTaskSS.TRLDTR,DemoLDT_Sel mov ax,DemoTSS_Sel ltr ax ;装载TR mov ax,DemoData_Sel mov ds,ax ;装载其它数据段寄存器 mov ax,VideoBuf_Sel mov es,ax mov ax,XBuffer_Sel mov fs,ax mov ax,XBuffer_Sel mov gs,ax int 0ffh ;接收要模拟的异常类型号 mov al,BYTE PTR fs:KeyASCII ;按接收的字符模拟异常号 cmp al,'0' jnz Demo4 mov ax,2000 mov cl,2 ;模拟除法出错故障 div cl ;该指令长2字节 jmp Over Demo4: cmp al,'4' jnz Demo11 mov al,100 add al,50 into ;模拟溢出陷阱 JMP OVER Demo11: cmp al,'B' jnz Demo12 mov ax,TestNPS_Sel ;模拟段不存在故障 mov gs,ax ;该指令长2字节 JMP Over Demo12: cmp al,'C' jnz Demo13 mov ebp,esp ;模拟堆栈出错故障 mov al,[ebp] ;该指令长4字节 jmp Over Demo13: mov ax,DemoTSS_Sel ;模拟通用保护故障 mov gs,ax ;该指令长2字节 Over: ;转临时代码段 JUMP16 TempCode_Sel,<OFFSET ToDos> DemoBegin ENDP ;---------------------------------------------------------------------------- DemoCodeLen = $ DemoCodeSeg ENDS ;---------------------------------------------------------------------------- TempCodeSeg SEGMENT PARA USE16 ;临时任务的代码段 ASSUME CS:TempCodeSeg ;---------------------------------------------------------------------------- Virtual PROC FAR JUMP16 DemoCode_Sel,DemoBegin ;转演示任务 ToDos: mov ax,Normal_Sel ;恢复实方式段描述符高速缓存 mov ds,ax mov es,ax mov fs,ax mov gs,ax mov ss,ax mov eax,cr0 ;准备返回实模式 and al,11111110b mov cr0,eax JUMP16 <SEG Real>,<OFFSET Real> Virtual ENDP ;---------------------------------------------------------------------------- TempCodeSeg ENDS ;============================================================================ RDataSeg SEGMENT PARA USE16 ;实方式数据段 VGDTR PDesc <GDTLen-1,> ;GDT伪描述符 VIDTR PDesc <IDTLen-1,> ;IDT伪描述符 NORVIDTR PDesc <3ffh,> ;用于保存原IDTR值 SPVar DW ? ;用于保存实方式下的SP SSVar DW ? ;用于保存实方式下的SS Mess DB 'Press a key[0,4,B,C,D]:$';提示信息 RDataSeg ENDS ;---------------------------------------------------------------------------- RCodeSeg SEGMENT PARA USE16 ;实方式代码段 ASSUME CS:RCodeSeg,DS:RDataSeg ;---------------------------------------------------------------------------- Start PROC mov ax,RDataSeg mov ds,ax cld call InitGDT ;初始化全局描述符表GDT call InitIDT ;初始化中断描述符表IDT mov ax,GKeyLDTSeg mov fs,ax mov cx,GKeyLDNum mov si,OFFSET GLDT CALL InitLDT mov ax,DemoLDTSeg mov fs,ax mov cx,DemoLDNum mov si,OFFSET DLDT CALL InitLDT mov SSVar,ss ;保存堆栈指针 mov SPVar,sp lgdt QWORD PTR VGDTR ;装载GDTR sidt QWORD PTR NORVIDTR ;保存IDTR cli ;关中断 lidt QWORD PTR VIDTR ;装载IDTR mov eax,cr0 or al,1 mov cr0,eax JUMP16 <TempCode_Sel>,<OFFSET Virtual> Real: mov ax,RDataSeg mov ds,ax lss sp,DWORD PTR SPVar ;又回到实方式 lidt QWORD PTR NORVIDTR sti mov ax,4c00h int 21h Start ENDP ;---------------------------------------------------------------------------- InitGDT PROC push ds mov ax,GDTSeg mov ds,ax mov cx,GDNum mov si,OFFSET EFFGDT InitG: mov ax,[si].BaseL movzx eax,ax shl eax,4 shld edx,eax,16 mov WORD PTR [si].BaseL,ax mov BYTE PTR [si].BaseM,dl mov BYTE PTR [si].BaseH,dh add si,SIZE Desc loop InitG pop ds mov bx,16 mov ax,GDTSeg mul bx mov WORD PTR VGDTR.Base,ax mov WORD PTR VGDTR.Base+2,dx ret InitGDT ENDP ;---------------------------------------------------------------------------- InitIDT PROC mov bx,16 mov ax,IDTSeg mul bx mov WORD PTR VIDTR.Base,ax mov WORD PTR VIDTR.Base+2,dx ret InitIDT ENDP ;---------------------------------------------------------------------------- ;入口参数:FS:SI=第一个要初始化的描述符,CX=要初始化的描述符数 ;---------------------------------------------------------------------------- InitLDT PROC ILDT: mov ax,WORD PTR FS:[si].BaseL movzx eax,ax shl eax,4 shld edx,eax,16 mov WORD PTR fs:[si].BaseL,ax mov BYTE PTR fs:[si].BaseM,dl mov BYTE PTR fs:[si].BaseH,dh add si,SIZE Desc loop ILDT ret InitLDT ENDP ;---------------------------------------------------------------------------- RCodeSeg ENDS END Start
参考资料 | 书 名 | 出 版 社 | 作 者 |
《保护方式下的80386及其编程》 | 清华大学出版社 | 周明德主编 | |
《80X86汇编语言程序设计教程》 | 清华大学出版社 | 扬季文主编 | |
《32位系统软件编程指南》 | 电子工业出版社 | 程荷、武航翻译 |